#include "driver_function.h"
#include "ch32v30x.h"
#include "string.h"

/**
 * PE0 ----> UART4_TX
 * PE1 ----> UART4_RX
 *
 **/

uint8_t driver_uart_wifi_dma_rx_buf[DRIVER_UART_DMA_LEN] = { 0 };

void driver_wifi_init()
{
    GPIO_InitTypeDef  GPIO_InitStructure  = { 0 };
    USART_InitTypeDef USART_InitStructure = { 0 };

    NVIC_InitTypeDef  NVIC_InitStructure  = { 0 };
    DMA_InitTypeDef   DMA_InitStructure   = { 0 };

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOE, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);

    GPIO_PinRemapConfig(GPIO_FullRemap_USART4, ENABLE);


    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOE, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOE, &GPIO_InitStructure);

    USART_InitStructure.USART_BaudRate            = 115200;
    USART_InitStructure.USART_WordLength          = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits            = USART_StopBits_1;
    USART_InitStructure.USART_Parity              = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode                = USART_Mode_Tx | USART_Mode_Rx;
    USART_Init(UART4, &USART_InitStructure);

    USART_ITConfig(UART4, USART_IT_IDLE, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 7;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    DMA_DeInit(DMA2_Channel5);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&UART4->DATAR);
    DMA_InitStructure.DMA_MemoryBaseAddr = 0;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = 0;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA2_Channel5, &DMA_InitStructure);


    DMA_DeInit(DMA2_Channel3); //UART4_RX
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(UART4->DATAR);
    DMA_InitStructure.DMA_MemoryBaseAddr     = (u32)driver_uart_wifi_dma_rx_buf;
    DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize         = DRIVER_UART_DMA_LEN;
    DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode               = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority           = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M                = DMA_M2M_Disable;
    DMA_Init(DMA2_Channel3, &DMA_InitStructure);
    DMA_Cmd(DMA2_Channel3, ENABLE);

    DMA_ITConfig(DMA2_Channel3, DMA_IT_TC, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel                   = DMA2_Channel3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    DMA_Cmd(DMA2_Channel5, DISABLE); /* UART4 Tx */
    USART_Cmd(UART4, ENABLE);
    USART_DMACmd(UART4, USART_DMAReq_Tx | USART_DMAReq_Rx,ENABLE);
}


void driver_wifi_send_cmd(uint8_t *data, uint16_t len)
{
    while (DMA_GetCurrDataCounter(DMA2_Channel5) > 0);

    DMA_Cmd(DMA2_Channel5, DISABLE);
    DMA_SetCurrDataCounter(DMA2_Channel5,len);
    DMA2_Channel5->MADDR = (uint32_t)data;
    DMA_Cmd(DMA2_Channel5, ENABLE);
}

void UART4_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void UART4_IRQHandler(void)
{
    driver_uart_obj m_driver_uart4;
    strncpy((char*)m_driver_uart4.rx_name, "usart4", sizeof(m_driver_uart4.rx_name) - 1);
    m_driver_uart4.rx_name[sizeof(m_driver_uart4.rx_name) - 1] = '\0';
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    if(USART_GetITStatus(UART4, USART_IT_IDLE) != RESET) //
    {
        DMA_Cmd(DMA2_Channel3, DISABLE);
        m_driver_uart4.rx_len = DRIVER_UART_DMA_LEN - DMA_GetCurrDataCounter(DMA2_Channel3);
        if (m_driver_uart4.rx_len > 0 && m_driver_uart4.rx_len <= DRIVER_UART_DMA_LEN)
        memcpy(m_driver_uart4.rx_date,driver_uart_wifi_dma_rx_buf,m_driver_uart4.rx_len);
        xQueueSendFromISR(driver_uart_get_queue_handle(),&m_driver_uart4,0);//send recv date
        DMA_SetCurrDataCounter(DMA2_Channel3, DRIVER_UART_DMA_LEN);
        DMA_Cmd(DMA2_Channel3, ENABLE);
        USART_ReceiveData(UART4);
    }
    if (xHigherPriorityTaskWoken) {
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}

void DMA2_Channel3_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void DMA2_Channel3_IRQHandler(void)
{
    driver_uart_obj m_driver_uart4;
    strncpy((char*)m_driver_uart4.rx_name, "usart4", sizeof(m_driver_uart4.rx_name) - 1);
    m_driver_uart4.rx_name[sizeof(m_driver_uart4.rx_name) - 1] = '\0';
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    DMA_Cmd(DMA2_Channel3, DISABLE);
    m_driver_uart4.rx_len = DRIVER_UART_DMA_LEN - DMA_GetCurrDataCounter(DMA2_Channel3);
    if (m_driver_uart4.rx_len > 0 && m_driver_uart4.rx_len <= DRIVER_UART_DMA_LEN)
    memcpy(m_driver_uart4.rx_date,driver_uart_wifi_dma_rx_buf,m_driver_uart4.rx_len);
    xQueueSendFromISR(driver_uart_get_queue_handle(),&m_driver_uart4,0);//send recv date
    DMA_SetCurrDataCounter(DMA2_Channel3, DRIVER_UART_DMA_LEN);
    DMA_Cmd(DMA2_Channel3, ENABLE);
    DMA_ClearITPendingBit(DMA2_IT_TC3);
    if (xHigherPriorityTaskWoken) {
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}

